package top.zywork.service.impl;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import top.zywork.dao.AccountDetailDAO;
import top.zywork.dao.PlatformAccountDetailDAO;
import top.zywork.dao.UserWalletDAO;
import top.zywork.dos.AccountDetailDO;
import top.zywork.dos.PlatformAccountDetailDO;
import top.zywork.enums.*;
import top.zywork.service.PayNotifyService;
import top.zywork.service.PayService;
import top.zywork.service.SysConfigService;
import top.zywork.vo.ResponseStatusVO;
import top.zywork.weixin.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.math.BigDecimal;
import java.util.Map;

/**
 * 支付服务接口实现类<br/>
 *
 * 创建于2019-01-15<br/>
 *
 * @author 王振宇
 * @version 1.0
 */
@Slf4j
public abstract class AbstractPayService implements PayService {

    private UserWalletDAO userWalletDAO;

    private AccountDetailDAO accountDetailDAO;

    private PlatformAccountDetailDAO platformAccountDetailDAO;

    private SysConfigService sysConfigService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResponseStatusVO payByBalance(Long userId, String transactionNo, int totalFee, FundsChangeTypeEnum userFundsChangeTypeEnum,
                                         FundsChangeTypeEnum platformFundsChangeType, String accountRemark) {
        BigDecimal amount = new BigDecimal(totalFee / 100.0).setScale(2, BigDecimal.ROUND_HALF_UP);
        int updatedRows = userWalletDAO.updateWalletOut(userId, amount);
        if (updatedRows == 0) {
            return ResponseStatusVO.dataError("可用余额不足", null);
        }
        accountDetailDAO.save(getAccountDetailDO(userId, transactionNo, amount.negate(), IncomeOutgoingTypeEnum.OUTGOING.getValue().byteValue(),
                userFundsChangeTypeEnum, PaymentTypeEnum.WALLET_PAY, AccountStatusEnum.WAIT_CONFIRM, accountRemark));
        platformAccountDetailDAO.save(getPlatformAccountDetail(userId, transactionNo, amount, IncomeOutgoingTypeEnum.INCOME.getValue().byteValue(),
                platformFundsChangeType, PaymentTypeEnum.WALLET_PAY, AccountStatusEnum.WAIT_CONFIRM, accountRemark));
        return ResponseStatusVO.ok("余额支付成功", null);
    }

    @Override
    public ResponseStatusVO payByGzhWxpay(String openid, String orderNo, String ip, String body, String attach, int totalFee, String payNotifyUrl) {
        WeixinGzhConfig weixinGzhConfig = sysConfigService.getByName(SysConfigEnum.WEIXIN_GZH_CONFIG.getValue(), WeixinGzhConfig.class);
        WXPayConfig wxPayConfig = sysConfigService.getByName(SysConfigEnum.WX_PAY_CONFIG.getValue(), WXPayConfig.class);
        Map<String, String> unifiedOrderResult = WeixinPayUtils.unifiedOrder(weixinGzhConfig.getAppId(), wxPayConfig.getMchId(),
                wxPayConfig.getApiSecret(), openid, orderNo, ip, body, attach, totalFee, payNotifyUrl == null ? wxPayConfig.getPayNotifyUrl() : payNotifyUrl);
        if (!WeixinPayUtils.isReturnSuccess(unifiedOrderResult)) {
            log.error("weixin gzh unified order fail");
            return ResponseStatusVO.error("微信公众号端统一下单请求失败", null);
        }
        if (!WeixinPayUtils.isResultSuccess(unifiedOrderResult)) {
            log.error("weixin gzh unified order fail, err code: {}, err code des: {}", WeixinPayUtils.errCode(unifiedOrderResult), WeixinPayUtils.errCodeDes(unifiedOrderResult));
            return ResponseStatusVO.error("微信公众号端统一下单失败", null);
        }
        PayData payData = WeixinPayUtils.payData(WeixinPayUtils.payDataMap(weixinGzhConfig.getAppId(), wxPayConfig.getApiSecret(), unifiedOrderResult));
        return ResponseStatusVO.ok("已获取公众号JS发起支付请求需要的数据", payData);
    }

    @Override
    public ResponseStatusVO payByGzhWxpayCoupon(String openid, String orderNo, String ip, String body, String detail, String attach, int totalFee, String goodsTag, String payNotifyUrl) {
        WeixinGzhConfig weixinGzhConfig = sysConfigService.getByName(SysConfigEnum.WEIXIN_GZH_CONFIG.getValue(), WeixinGzhConfig.class);
        WXPayConfig wxPayConfig = sysConfigService.getByName(SysConfigEnum.WX_PAY_CONFIG.getValue(), WXPayConfig.class);
        Map<String, String> unifiedOrderResult = WeixinPayUtils.unifiedOrderCoupon(weixinGzhConfig.getAppId(), wxPayConfig.getMchId(),
                wxPayConfig.getApiSecret(), openid, orderNo, ip, body, detail, attach, totalFee, goodsTag, payNotifyUrl == null ? wxPayConfig.getPayNotifyUrl() : payNotifyUrl);
        if (!WeixinPayUtils.isReturnSuccess(unifiedOrderResult)) {
            log.error("weixin gzh unified order coupon fail");
            return ResponseStatusVO.error("微信公众号端统一下单请求(带优惠)失败", null);
        }
        if (!WeixinPayUtils.isResultSuccess(unifiedOrderResult)) {
            log.error("weixin gzh unified order coupon fail, err code: {}, err code des: {}", WeixinPayUtils.errCode(unifiedOrderResult), WeixinPayUtils.errCodeDes(unifiedOrderResult));
            return ResponseStatusVO.error("微信公众号端统一下单(带优惠)失败", null);
        }
        PayData payData = WeixinPayUtils.payData(WeixinPayUtils.payDataMap(weixinGzhConfig.getAppId(), wxPayConfig.getApiSecret(), unifiedOrderResult));
        return ResponseStatusVO.ok("已获取公众号JS发起支付请求需要的数据(带优惠)", payData);
    }

    @Override
    public ResponseStatusVO payByXcxWxpay(String openid, String orderNo, String ip, String body, String attach, int totalFee, String payNotifyUrl) {
        WeixinXcxConfig weixinXcxConfig = sysConfigService.getByName(SysConfigEnum.WEIXIN_XCX_CONFIG.getValue(), WeixinXcxConfig.class);
        WXPayConfig wxPayConfig = sysConfigService.getByName(SysConfigEnum.WX_PAY_CONFIG.getValue(), WXPayConfig.class);
        Map<String, String> unifiedOrderResult = WeixinPayUtils.unifiedOrder(weixinXcxConfig.getAppId(), wxPayConfig.getMchId(),
                wxPayConfig.getApiSecret(), openid, orderNo, ip, body, attach, totalFee, payNotifyUrl == null ? wxPayConfig.getPayNotifyUrl() : payNotifyUrl);
        if (!WeixinPayUtils.isReturnSuccess(unifiedOrderResult)) {
            log.error("weixin xcx unified order fail");
            return ResponseStatusVO.error("微信小程序端统一下单请求失败", null);
        }
        if (!WeixinPayUtils.isResultSuccess(unifiedOrderResult)) {
            log.error("weixin xcx unified order error, err code: {}, err code des: {}", WeixinPayUtils.errCode(unifiedOrderResult), WeixinPayUtils.errCodeDes(unifiedOrderResult));
            return ResponseStatusVO.error("微信小程序端统一下单失败", null);
        }
        PayData payData = WeixinPayUtils.payData(WeixinPayUtils.payDataMap(weixinXcxConfig.getAppId(), wxPayConfig.getApiSecret(), unifiedOrderResult));
        return ResponseStatusVO.ok("已获取小程序API发起支付请求需要的数据", payData);
    }

    @Override
    public ResponseStatusVO payByXcxWxpayCoupon(String openid, String orderNo, String ip, String body, String detail, String attach, int totalFee, String goodsTag, String payNotifyUrl) {
        WeixinXcxConfig weixinXcxConfig = sysConfigService.getByName(SysConfigEnum.WEIXIN_XCX_CONFIG.getValue(), WeixinXcxConfig.class);
        WXPayConfig wxPayConfig = sysConfigService.getByName(SysConfigEnum.WX_PAY_CONFIG.getValue(), WXPayConfig.class);
        Map<String, String> unifiedOrderResult = WeixinPayUtils.unifiedOrderCoupon(weixinXcxConfig.getAppId(), wxPayConfig.getMchId(),
                wxPayConfig.getApiSecret(), openid, orderNo, ip, body, detail, attach, totalFee, goodsTag, payNotifyUrl == null ? wxPayConfig.getPayNotifyUrl() : payNotifyUrl);
        if (!WeixinPayUtils.isReturnSuccess(unifiedOrderResult)) {
            log.error("weixin xcx unified order coupon fail");
            return ResponseStatusVO.error("微信小程序端统一下单请求(带优惠)失败", null);
        }
        if (!WeixinPayUtils.isResultSuccess(unifiedOrderResult)) {
            log.error("weixin xcx unified order coupon error, err code: {}, err code des: {}", WeixinPayUtils.errCode(unifiedOrderResult), WeixinPayUtils.errCodeDes(unifiedOrderResult));
            return ResponseStatusVO.error("微信小程序端统一下单(带优惠)失败", null);
        }
        PayData payData = WeixinPayUtils.payData(WeixinPayUtils.payDataMap(weixinXcxConfig.getAppId(), wxPayConfig.getApiSecret(), unifiedOrderResult));
        return ResponseStatusVO.ok("已获取小程序API发起支付请求需要的数据(带优惠)", payData);
    }

    @Override
    public void payByWxNotify(HttpServletRequest request, HttpServletResponse response, PayNotifyService payNotifyService) {
        Map<String, String> payResultMap = WeixinPayUtils.payResultMap(request);
        if (payResultMap != null) {
            PayResult payResult  = WeixinPayUtils.payResult(payResultMap);
            log.info("pay result: {}", payResult);
            if (WeixinPayUtils.isReturnSuccess(payResultMap)) {
                if (WeixinPayUtils.isResultSuccess(payResultMap)) {
                    // 支付业务结果成功
                    payNotifyService.wxPaySuccessNotify(payResult);
                } else {
                    // 支付业务结果失败
                    payNotifyService.wxPayFailNotify(payResult);
                }
            }
            WeixinPayUtils.responsePayNotify(response);
        }
    }

    @Override
    public ResponseStatusVO refundByGzhWxpay(String transactionNo, String outRefundNo, int totalFee, int refundFee, String refundDesc, String refundNotifyUrl) {
        WeixinGzhConfig weixinGzhConfig = sysConfigService.getByName(SysConfigEnum.WEIXIN_GZH_CONFIG.getValue(), WeixinGzhConfig.class);
        WXPayConfig wxPayConfig = sysConfigService.getByName(SysConfigEnum.WX_PAY_CONFIG.getValue(), WXPayConfig.class);
        Map<String, String> refundResult = WeixinPayUtils.refund(weixinGzhConfig.getAppId(), wxPayConfig.getMchId(),
                wxPayConfig.getApiSecret(), transactionNo, outRefundNo, totalFee, refundFee, refundDesc,
                refundNotifyUrl == null ? wxPayConfig.getRefundNotifyUrl() : refundNotifyUrl, wxPayConfig.getCertPath());
        if (!WeixinPayUtils.isReturnSuccess(refundResult)) {
            log.error("weixin gzh refund fail");
            return ResponseStatusVO.error("微信公众号端退款申请请求失败", null);
        }
        if (!WeixinPayUtils.isResultSuccess(refundResult)) {
            log.error("weixin gzh refund fail, err code: {}, err code des: {}", WeixinPayUtils.errCode(refundResult), WeixinPayUtils.errCodeDes(refundResult));
            return ResponseStatusVO.error("微信公众号端退款申请失败", null);
        }
        return ResponseStatusVO.ok("微信公众号端退款申请成功", null);
    }

    @Override
    public ResponseStatusVO refundByXcxWxpay(String transactionNo, String outRefundNo, int totalFee, int refundFee, String refundDesc, String refundNotifyUrl) {
        WeixinXcxConfig weixinXcxConfig = sysConfigService.getByName(SysConfigEnum.WEIXIN_XCX_CONFIG.getValue(), WeixinXcxConfig.class);
        WXPayConfig wxPayConfig = sysConfigService.getByName(SysConfigEnum.WX_PAY_CONFIG.getValue(), WXPayConfig.class);
        Map<String, String> refundResult = WeixinPayUtils.refund(weixinXcxConfig.getAppId(), wxPayConfig.getMchId(),
                wxPayConfig.getApiSecret(), transactionNo, outRefundNo, totalFee, refundFee, refundDesc,
                refundNotifyUrl == null ? wxPayConfig.getRefundNotifyUrl() : refundNotifyUrl, wxPayConfig.getCertPath());
        if (!WeixinPayUtils.isReturnSuccess(refundResult)) {
            log.error("weixin xcx refunc fail");
            return ResponseStatusVO.error("微信小程序端退款申请请求失败", null);
        }
        if (!WeixinPayUtils.isResultSuccess(refundResult)) {
            log.error("weixin xcx refund error, err code: {}, err code des: {}", WeixinPayUtils.errCode(refundResult), WeixinPayUtils.errCodeDes(refundResult));
            return ResponseStatusVO.error("微信小程序端退款申请失败", null);
        }
        return ResponseStatusVO.ok("微信小程序端退款申请成功", null);
    }

    @Override
    public void refundByWxNotify(HttpServletRequest request, HttpServletResponse response, PayNotifyService payNotifyService) {
        Map<String, String> refundResultMap = WeixinPayUtils.refundResultMap(request);
        if (refundResultMap != null) {
            RefundResult refundResult  = WeixinPayUtils.refundResult(refundResultMap);
            log.info("refund result: {}", refundResult);
            if (WeixinPayUtils.isReturnSuccess(refundResultMap)) {
                if (WeixinPayUtils.isResultSuccess(refundResultMap)) {
                    // 退款结果成功
                    payNotifyService.wxRefundSuccessNotify(refundResult);
                } else {
                    // 退款结果失败
                    payNotifyService.wxRefundFailNotify(refundResult);
                }
            }
        }
    }

    @Override
    public ResponseStatusVO payByAlipay() {
        return null;
    }

    @Override
    public ResponseStatusVO payByUnionpay() {
        return null;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResponseStatusVO transferByBalance(Long userId, String transactionNo, int totalFee, FundsChangeTypeEnum userFundsChangeTypeEnum,
                                              FundsChangeTypeEnum platformFundsChangeType, String accountRemark) {
        BigDecimal amount = new BigDecimal(totalFee / 100.0).setScale(2, BigDecimal.ROUND_HALF_UP);
        userWalletDAO.updateWalletIn(userId, amount);
        accountDetailDAO.save(getAccountDetailDO(userId, transactionNo, amount, IncomeOutgoingTypeEnum.INCOME.getValue().byteValue(),
                userFundsChangeTypeEnum, PaymentTypeEnum.WALLET_PAY,AccountStatusEnum.ALREADY_CONFIRM, accountRemark));
        platformAccountDetailDAO.save(getPlatformAccountDetail(userId, transactionNo, amount.negate(), IncomeOutgoingTypeEnum.OUTGOING.getValue().byteValue(),
                platformFundsChangeType, PaymentTypeEnum.WALLET_PAY,AccountStatusEnum.ALREADY_CONFIRM, accountRemark));
        return ResponseStatusVO.ok("余额支付成功", null);
    }

    @Override
    public ResponseStatusVO sendRedpackByGzh(Long userId, String openid, String billNo, String ip, String sendName, int totalAmount,
                                             int totalNum, String wishing, String actName, String remark, String sceneId,
                                             FundsChangeTypeEnum userFundsChangeTypeEnum, FundsChangeTypeEnum platformFundsChangeType) {
        WeixinGzhConfig weixinGzhConfig = sysConfigService.getByName(SysConfigEnum.WEIXIN_GZH_CONFIG.getValue(), WeixinGzhConfig.class);
        WXPayConfig wxPayConfig = sysConfigService.getByName(SysConfigEnum.WX_PAY_CONFIG.getValue(), WXPayConfig.class);
        Map<String, String> redpackResultMap = WeixinPayUtils.sendRedpackGzh(weixinGzhConfig.getAppId(), wxPayConfig.getMchId(),
                wxPayConfig.getApiSecret(), openid, ip, billNo, sendName, totalAmount, totalNum, wishing, actName, remark, sceneId, wxPayConfig.getCertPath());
        if (!WeixinPayUtils.isReturnSuccess(redpackResultMap)) {
            log.error("weixin gzh send redpack fail");
        }
        BigDecimal amount = new BigDecimal(totalAmount / 100.0).setScale(2, BigDecimal.ROUND_HALF_UP);
        if (!WeixinPayUtils.isResultSuccess(redpackResultMap)) {
            log.error("weixin gzh send redpack error, err code: {}, err code des: {}", WeixinPayUtils.errCode(redpackResultMap), WeixinPayUtils.errCodeDes(redpackResultMap));
            userWalletDAO.updateWalletIn(userId, amount);
            accountDetailDAO.save(getAccountDetailDO(userId, billNo, amount, IncomeOutgoingTypeEnum.INCOME.getValue().byteValue(),
                    userFundsChangeTypeEnum, PaymentTypeEnum.WALLET_PAY,AccountStatusEnum.ALREADY_CONFIRM, remark + "，微信红包支付失败，转余额支付"));
            platformAccountDetailDAO.save(getPlatformAccountDetail(userId, billNo, amount.negate(), IncomeOutgoingTypeEnum.OUTGOING.getValue().byteValue(),
                    platformFundsChangeType, PaymentTypeEnum.WALLET_PAY,AccountStatusEnum.ALREADY_CONFIRM, remark + "，微信红包支付失败，转余额支付"));
            return ResponseStatusVO.error("微信公众号端发送普通红包失败，金额转入用户余额中", null);
        }
        RedpackResult redpackResult = WeixinPayUtils.redpackResult(redpackResultMap);
        accountDetailDAO.save(getAccountDetailDO(userId, redpackResult.getSendListid(), amount, IncomeOutgoingTypeEnum.INCOME.getValue().byteValue(),
                userFundsChangeTypeEnum, PaymentTypeEnum.WEIXIN_PAY, AccountStatusEnum.ALREADY_CONFIRM, remark));
        platformAccountDetailDAO.save(getPlatformAccountDetail(userId, redpackResult.getSendListid(), amount.negate(), IncomeOutgoingTypeEnum.OUTGOING.getValue().byteValue(),
                platformFundsChangeType, PaymentTypeEnum.WEIXIN_PAY, AccountStatusEnum.ALREADY_CONFIRM, remark));
        return ResponseStatusVO.ok("微信公众号端发送普通红包成功", redpackResult);
    }

    @Override
    public ResponseStatusVO transferToPersonalGzh(Long userId, String openid, String ip, String partnerTradeNo, int amount, String checkName, String desc, String accountRemark,
                                                  FundsChangeTypeEnum userFundsChangeTypeEnum, FundsChangeTypeEnum platformFundsChangeType) {
        WeixinGzhConfig weixinGzhConfig = sysConfigService.getByName(SysConfigEnum.WEIXIN_GZH_CONFIG.getValue(), WeixinGzhConfig.class);
        WXPayConfig wxPayConfig = sysConfigService.getByName(SysConfigEnum.WX_PAY_CONFIG.getValue(), WXPayConfig.class);
        Map<String, String> transferResultMap = WeixinPayUtils.transferToPersonal(weixinGzhConfig.getAppId(), wxPayConfig.getMchId(),
                wxPayConfig.getApiSecret(), openid, ip, partnerTradeNo, amount, checkName, desc, wxPayConfig.getCertPath());
        if (!WeixinPayUtils.isReturnSuccess(transferResultMap)) {
            log.error("weixin gzh transfer to personal fail");
        }
        BigDecimal totalAmount = new BigDecimal(amount / 100.0).setScale(2, BigDecimal.ROUND_HALF_UP);
        if (!WeixinPayUtils.isResultSuccess(transferResultMap)) {
            log.error("weixin gzh transfer to personal error, err code: {}, err code des: {}", WeixinPayUtils.errCode(transferResultMap), WeixinPayUtils.errCodeDes(transferResultMap));
            userWalletDAO.updateWalletIn(userId, totalAmount);
            accountDetailDAO.save(getAccountDetailDO(userId, partnerTradeNo, totalAmount, IncomeOutgoingTypeEnum.INCOME.getValue().byteValue(),
                    userFundsChangeTypeEnum, PaymentTypeEnum.WALLET_PAY,AccountStatusEnum.ALREADY_CONFIRM, accountRemark + "，微信企业付款失败，转余额支付"));
            platformAccountDetailDAO.save(getPlatformAccountDetail(userId, partnerTradeNo, totalAmount.negate(), IncomeOutgoingTypeEnum.OUTGOING.getValue().byteValue(),
                    platformFundsChangeType, PaymentTypeEnum.WALLET_PAY,AccountStatusEnum.ALREADY_CONFIRM, accountRemark + "，微信企业付款失败，转余额支付"));
            return ResponseStatusVO.error("微信公众号端企业付款到个人失败，金额转入用户余额中", null);
        }
        TransferToPersonalResult transferToPersonalResult = WeixinPayUtils.transferToPersonalResult(transferResultMap);
        accountDetailDAO.save(getAccountDetailDO(userId, transferToPersonalResult.getPaymentNo(), totalAmount, IncomeOutgoingTypeEnum.INCOME.getValue().byteValue(),
                userFundsChangeTypeEnum, PaymentTypeEnum.WEIXIN_PAY, AccountStatusEnum.ALREADY_CONFIRM, accountRemark));
        platformAccountDetailDAO.save(getPlatformAccountDetail(userId, transferToPersonalResult.getPaymentNo(), totalAmount.negate(), IncomeOutgoingTypeEnum.OUTGOING.getValue().byteValue(),
                platformFundsChangeType, PaymentTypeEnum.WEIXIN_PAY, AccountStatusEnum.ALREADY_CONFIRM, accountRemark));
        return ResponseStatusVO.ok("微信公众号端企业付款到个人成功", transferToPersonalResult);
    }

    @Override
    public ResponseStatusVO transferToPersonalXcx(Long userId, String openid, String ip, String partnerTradeNo, int amount, String checkName, String desc, String accountRemark,
                                                  FundsChangeTypeEnum userFundsChangeTypeEnum, FundsChangeTypeEnum platformFundsChangeType) {
        WeixinXcxConfig weixinXcxConfig = sysConfigService.getByName(SysConfigEnum.WEIXIN_XCX_CONFIG.getValue(), WeixinXcxConfig.class);
        WXPayConfig wxPayConfig = sysConfigService.getByName(SysConfigEnum.WX_PAY_CONFIG.getValue(), WXPayConfig.class);
        Map<String, String> transferResultMap = WeixinPayUtils.transferToPersonal(weixinXcxConfig.getAppId(), wxPayConfig.getMchId(),
                wxPayConfig.getApiSecret(), openid, ip, partnerTradeNo, amount, checkName, desc, wxPayConfig.getCertPath());
        if (!WeixinPayUtils.isReturnSuccess(transferResultMap)) {
            log.error("weixin xcx transfer to personal fail");
        }
        BigDecimal totalAmount = new BigDecimal(amount / 100.0).setScale(2, BigDecimal.ROUND_HALF_UP);
        if (!WeixinPayUtils.isResultSuccess(transferResultMap)) {
            log.error("weixin xcx transfer to personal error, err code: {}, err code des: {}", WeixinPayUtils.errCode(transferResultMap), WeixinPayUtils.errCodeDes(transferResultMap));
            userWalletDAO.updateWalletIn(userId, totalAmount);
            accountDetailDAO.save(getAccountDetailDO(userId, partnerTradeNo, totalAmount, IncomeOutgoingTypeEnum.INCOME.getValue().byteValue(),
                    userFundsChangeTypeEnum, PaymentTypeEnum.WALLET_PAY,AccountStatusEnum.ALREADY_CONFIRM, accountRemark + "，微信企业付款失败，转余额支付"));
            platformAccountDetailDAO.save(getPlatformAccountDetail(userId, partnerTradeNo, totalAmount.negate(), IncomeOutgoingTypeEnum.OUTGOING.getValue().byteValue(),
                    platformFundsChangeType, PaymentTypeEnum.WALLET_PAY,AccountStatusEnum.ALREADY_CONFIRM, accountRemark + "，微信企业付款失败，转余额支付"));
            return ResponseStatusVO.error("微信小程序企业付款到个人失败，金额转入用户余额中", null);
        }
        TransferToPersonalResult transferToPersonalResult = WeixinPayUtils.transferToPersonalResult(transferResultMap);
        accountDetailDAO.save(getAccountDetailDO(userId, transferToPersonalResult.getPaymentNo(), totalAmount, IncomeOutgoingTypeEnum.INCOME.getValue().byteValue(),
                userFundsChangeTypeEnum, PaymentTypeEnum.WEIXIN_PAY, AccountStatusEnum.ALREADY_CONFIRM, accountRemark));
        platformAccountDetailDAO.save(getPlatformAccountDetail(userId, transferToPersonalResult.getPaymentNo(), totalAmount.negate(), IncomeOutgoingTypeEnum.OUTGOING.getValue().byteValue(),
                platformFundsChangeType, PaymentTypeEnum.WEIXIN_PAY, AccountStatusEnum.ALREADY_CONFIRM, accountRemark));
        return ResponseStatusVO.ok("微信小程序企业付款到个人成功", transferToPersonalResult);
    }

    @Override
    public ResponseStatusVO withdrawToBankcardHuman(Long userId, String transactionNo, int amount, String accountRemark) {
        BigDecimal totalAmount = new BigDecimal(amount / 100.0).setScale(2, BigDecimal.ROUND_HALF_UP);
        userWalletDAO.updateWalletOut(userId, totalAmount.negate());
        accountDetailDAO.save(getAccountDetailDO(userId, transactionNo, totalAmount, IncomeOutgoingTypeEnum.OUTGOING.getValue().byteValue(),
                FundsChangeTypeEnum.WITHDRAW, PaymentTypeEnum.WALLET_PAY, AccountStatusEnum.ALREADY_CONFIRM, accountRemark));
        return ResponseStatusVO.ok("人工提现到银行卡成功", null);
    }

    @Override
    public ResponseStatusVO withdrawToPersonalGzh(Long userId, String openid, String ip, String partnerTradeNo, int amount, String checkName, String desc, String accountRemark) {
        WeixinGzhConfig weixinGzhConfig = sysConfigService.getByName(SysConfigEnum.WEIXIN_GZH_CONFIG.getValue(), WeixinGzhConfig.class);
        WXPayConfig wxPayConfig = sysConfigService.getByName(SysConfigEnum.WX_PAY_CONFIG.getValue(), WXPayConfig.class);
        Map<String, String> transferResultMap = WeixinPayUtils.transferToPersonal(weixinGzhConfig.getAppId(), wxPayConfig.getMchId(),
                wxPayConfig.getApiSecret(), openid, ip, partnerTradeNo, amount, checkName, desc, wxPayConfig.getCertPath());
        if (!WeixinPayUtils.isReturnSuccess(transferResultMap)) {
            log.error("weixin gzh transfer to personal fail");
            return ResponseStatusVO.error("微信公众号端企业付款到个人请求失败", null);
        }
        if (!WeixinPayUtils.isResultSuccess(transferResultMap)) {
            log.error("weixin gzh transfer to personal error, err code: {}, err code des: {}", WeixinPayUtils.errCode(transferResultMap), WeixinPayUtils.errCodeDes(transferResultMap));
            return ResponseStatusVO.error("微信公众号端企业付款到个人失败", null);
        }
        TransferToPersonalResult transferToPersonalResult = WeixinPayUtils.transferToPersonalResult(transferResultMap);
        BigDecimal totalAmount = new BigDecimal(amount / 100.0).setScale(2, BigDecimal.ROUND_HALF_UP);
        userWalletDAO.updateWalletOut(userId, totalAmount);
        accountDetailDAO.save(getAccountDetailDO(userId, partnerTradeNo, totalAmount, IncomeOutgoingTypeEnum.OUTGOING.getValue().byteValue(),
                FundsChangeTypeEnum.WITHDRAW, PaymentTypeEnum.WALLET_PAY, AccountStatusEnum.ALREADY_CONFIRM, accountRemark + "，微信支付订单号：" + transferToPersonalResult.getPaymentNo()));
        return ResponseStatusVO.ok("微信公众号端企业付款到个人成功", transferToPersonalResult);
    }

    @Override
    public ResponseStatusVO withdrawToPersonalXcx(Long userId, String openid, String ip, String partnerTradeNo, int amount, String checkName, String desc, String accountRemark) {
        WeixinXcxConfig weixinXcxConfig = sysConfigService.getByName(SysConfigEnum.WEIXIN_XCX_CONFIG.getValue(), WeixinXcxConfig.class);
        WXPayConfig wxPayConfig = sysConfigService.getByName(SysConfigEnum.WX_PAY_CONFIG.getValue(), WXPayConfig.class);
        Map<String, String> transferResultMap = WeixinPayUtils.transferToPersonal(weixinXcxConfig.getAppId(), wxPayConfig.getMchId(),
                wxPayConfig.getApiSecret(), openid, ip, partnerTradeNo, amount, checkName, desc, wxPayConfig.getCertPath());
        if (!WeixinPayUtils.isReturnSuccess(transferResultMap)) {
            log.error("weixin xcx transfer to personal fail");
            return ResponseStatusVO.error("微信小程序企业付款到个人请求失败", null);
        }
        TransferToPersonalResult transferToPersonalResult = WeixinPayUtils.transferToPersonalResult(transferResultMap);
        if (!WeixinPayUtils.isResultSuccess(transferResultMap)) {
            log.error("weixin xcx transfer to personal error, err code: {}, err code des: {}", WeixinPayUtils.errCode(transferResultMap), WeixinPayUtils.errCodeDes(transferResultMap));
            return ResponseStatusVO.error("微信小程序企业付款到个人失败", null);
        }
        BigDecimal totalAmount = new BigDecimal(amount / 100.0).setScale(2, BigDecimal.ROUND_HALF_UP);
        userWalletDAO.updateWalletOut(userId, totalAmount);
        accountDetailDAO.save(getAccountDetailDO(userId, partnerTradeNo, totalAmount, IncomeOutgoingTypeEnum.OUTGOING.getValue().byteValue(),
                FundsChangeTypeEnum.WITHDRAW, PaymentTypeEnum.WALLET_PAY, AccountStatusEnum.ALREADY_CONFIRM, accountRemark + "，微信支付订单号：" + transferToPersonalResult.getPaymentNo()));
        return ResponseStatusVO.ok("微信小程序企业付款到个人成功", transferToPersonalResult);
    }

    public AccountDetailDO getAccountDetailDO(Long userId, String transactionNo, BigDecimal amount, byte type,
                                               FundsChangeTypeEnum subType, PaymentTypeEnum paymentTypeEnum, AccountStatusEnum accountStatusEnum, String remark) {
        return AccountDetailDO.builder()
                .userId(userId)
                .transactionNo(transactionNo)
                .amount(amount)
                .type(type)
                .subType(subType.getValue())
                .payType(paymentTypeEnum.getValue().byteValue())
                .accountStatus(accountStatusEnum.getValue().byteValue())
                .remark(remark).build();
    }

    public PlatformAccountDetailDO getPlatformAccountDetail(Long userId, String transactionNo, BigDecimal amount, byte type,
                                                             FundsChangeTypeEnum subType, PaymentTypeEnum paymentTypeEnum, AccountStatusEnum accountStatusEnum, String remark) {
        return PlatformAccountDetailDO.builder()
                .userId(userId)
                .transactionNo(transactionNo)
                .amount(amount)
                .type(type)
                .subType(subType.getValue())
                .payType(paymentTypeEnum.getValue().byteValue())
                .accountStatus(accountStatusEnum.getValue().byteValue())
                .remark(remark).build();
    }

    @Autowired
    public void setAccountDetailDAO(AccountDetailDAO accountDetailDAO) {
        this.accountDetailDAO = accountDetailDAO;
    }

    @Autowired
    public void setUserWalletDAO(UserWalletDAO userWalletDAO) {
        this.userWalletDAO = userWalletDAO;
    }

    @Autowired
    public void setPlatformAccountDetailDAO(PlatformAccountDetailDAO platformAccountDetailDAO) {
        this.platformAccountDetailDAO = platformAccountDetailDAO;
    }

    @Autowired
    public void setSysConfigService(SysConfigService sysConfigService) {
        this.sysConfigService = sysConfigService;
    }

}
